package com.mini.gateway.core.modules.route.service;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.mini.gateway.core.modules.route.dto.RouteDefined;
import com.mini.gateway.core.modules.route.entity.MiniRoute;
import com.mini.gateway.core.modules.route.enums.RouteType;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.filter.factory.RewritePathGatewayFilterFactory;
import org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionLocator;
import org.springframework.cloud.gateway.support.NameUtils;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;

import java.net.URI;
import java.util.ArrayList;
import java.util.List;

/**
 * MiniRouteDefinitionLocator
 *
 */
@Slf4j
@Component
public class MiniRouteDefinitionLocator implements RouteDefinitionLocator {

    // 数据库路由缓存
    private List<RouteDefined> cacheList = new ArrayList<>();

    @Autowired
    private DiscoveryClient discoveryClient;
    @Autowired
    private RouteService routeService;

    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        // 1.从数据库中路由配置，并缓存
        loadRouteList(false);

        // 2.新增的服务增加到列表中
        List<String> serviceList = discoveryClient.getServices();

        boolean isAdd;
        List<String> addServiceList = new ArrayList<>();
        for (String serviceId : serviceList) {
            isAdd = false;
            for (RouteDefined route : cacheList) {
                // 判定当前被发现的服务是否已经入库
               if (route.getType().equals(RouteType.DISCOVERY) && serviceId.equals(route.getName())) {
                   isAdd = true;
                   break;
               }
            }
            if (!isAdd) {
                addServiceList.add(serviceId);
            }
        }

        // 新发现的服务入库
        if (CollectionUtils.isNotEmpty(addServiceList)) {
            List<MiniRoute> newRouteList = new ArrayList<>();
            for (String serviceId : addServiceList) {
                MiniRoute tempRoute = new MiniRoute(RouteType.DISCOVERY, serviceId, "/" + serviceId, "lb://" + serviceId, 0);
                newRouteList.add(tempRoute);
            }
            addNewRoute(newRouteList);
        }

        log.info("MiniRouteDefinitionLocator --> getRouteDefinitions");
        return Flux.fromIterable(cacheList)
                .map(route -> {
                    RouteDefinition definition = new RouteDefinition();
                    definition.setId(route.getName());
                    definition.setUri(URI.create(route.getUri()));
                    definition.setOrder(route.getOrders());

                    // 路径谓词
                    PredicateDefinition predicate = new PredicateDefinition();
                    predicate.setName(NameUtils.normalizeRoutePredicateName(PathRoutePredicateFactory.class));
                    predicate.addArg("pattern", route.getPath()+"/**");
                    definition.getPredicates().add(predicate);

                    // 过滤器（将/xx替换成具体服务地址）
                    FilterDefinition filter = new FilterDefinition();
                    filter.setName(NameUtils.normalizeFilterFactoryName(RewritePathGatewayFilterFactory.class));
                    String regex = route.getPath()+"/(?<remaining>.*)";
                    filter.addArg("regexp", regex);
                    filter.addArg("replacement", "/${remaining}");
                    definition.getFilters().add(filter);
                    // 自定义过滤器
                    for (FilterDefinition _filter : route.getFilterList()) {
                        filter = new FilterDefinition();
                        filter.setName(_filter.getName());
                        filter.setArgs(_filter.getArgs());
                        definition.getFilters().add(filter);
                    }
                    return definition;
        });
    }

    /**
     * 从数据库同步自定义路由配置
     * @param isRefresh
     */
    synchronized public void loadRouteList(boolean isRefresh) {
        synchronized (cacheList) {
            if (CollectionUtils.isEmpty(cacheList) || isRefresh) {
                cacheList = routeService.getRoutes();
            }
        }
    }

    /**
     * 批量新增路由
     * @param routeList
     */
    public void addNewRoute(List<MiniRoute> routeList) {
        for (MiniRoute route : routeList) {
            PredicateDefinition predicate = new PredicateDefinition();
            predicate.setName(NameUtils.normalizeRoutePredicateName(PathRoutePredicateFactory.class));
            predicate.addArg("pattern", route.getPath()+"/**");
//            route.getPredicates().add(predicate);
            routeService.addRoute(route);
        }
        loadRouteList(true);
    }

    /**
     * 获取服务缓存配置
     * @return
     */
    public List<RouteDefined> getCacheList() {
        return cacheList;
    }

}
